home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK2.toast / Development Kits (Disc 2) / QuickDraw GX / Programming Stuff / Sample Code / Printing Samples / Printer Drivers… / CustomWriterGX / NewApp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-05  |  37.0 KB  |  1,290 lines  |  [TEXT/MPS ]

  1. /*
  2.     FILENAME
  3.         NewApp.c
  4.  
  5.     DESCRIPTION
  6.         Contains code for all of our message overrides (except the old-application
  7.         compatibility ones.) to implement custom buffering and
  8.         non-standard communications code in a QuickDraw GX printer
  9.         driver.  In this code, we write everything to disk (through our
  10.         own buffers) as an extended version 2 PICT file.
  11.  
  12.     COPYRIGHT
  13.         Copyright © 1995 Apple Computer, Inc.
  14.         All rights reserved.
  15.     
  16.     Modification history
  17.         10/04/95 - David Hayward -    Version 1.0.4 modified code so that
  18.                                     the driver can be build under MPW,
  19.                                     Metrowerks, and Symantec.  In general,
  20.                                     all that was required to do this was 
  21.                                     to add an inline-assembly jumptable
  22.                                     and to store all globals off of the
  23.                                     message manager instance context.
  24.                                     Also made a few changes so that the
  25.                                     driver can be rebuilt to support any
  26.                                     resolution by changing the #defines
  27.                                     kResolution and kPatStretch in
  28.                                     "CommonDefines.h"
  29.  
  30.         06/14/95 - Dave Hersey -    Version 1.0.3 to fix a bug in
  31.                                     CustomBufferingAndIO.c when creating
  32.                                     high-res PICTs, and to make the size
  33.                                     of buffers more flexible.
  34.  
  35.         05/26/95 - Dave Hersey -    Version 1.0.2 to add the new 'outp'
  36.                                     desktop printer resource so that
  37.                                     paper mismatch and manual feed
  38.                                     alerts are suppressed.  See the
  39.                                     SD_DefaultDesktopPrinter routine
  40.                                     for details.
  41.  
  42.         05/03/95 - Dave Hersey -    Version 1.0.1 to fix some minor bugs in
  43.                                     CustomBufferingAndIO.c.
  44.                                     Also fixes the following bugs in this file.
  45.                                     
  46.                                     * endPict opcodes not always word aligned
  47.                                     * current buffer not being reset on flush
  48.                                     * gxWriteData override could not handle a
  49.                                       simple flush by passing a nil data or
  50.                                       length parameter.
  51.                                     * gxFinishSendPage, gxCloseConnection, and
  52.                                       gxCleanupOpenConnection overrides were
  53.                                       doing work before forwarding their
  54.                                       messages which should have been done after
  55.                                       the forwards. 
  56.         01/14/95 - Dave Hersey -    Created from the shell of a hollowed-out
  57.                                     ImageWriter driver.
  58. */
  59.  
  60.  
  61. #include "GlobalData.h"
  62. #include "NewApp.h"
  63. #include "CommonDefines.h"
  64.  
  65.  
  66. // Prototypes for local functions.
  67. OSErr    CreateBuffers                ( void ) ;
  68. OSErr    DisposeBuffers                ( void ) ;
  69. OSErr    FlushBuffers                ( BufferGroupHdl buffGrpHdl ) ;
  70. OSErr    WriteFileData                ( void *dataBuffer, long dataLength ) ;
  71. OSErr    WriteEndOfPICTFile            ( void ) ;
  72. OSErr    WriteStartOfPICTFile        ( void ) ;
  73. OSErr    WriteBlankLines                ( long numBlankLinesToDo, gxRectangle *bandRect ) ;
  74.  
  75.  
  76. /*    -----------------------------------------------------------------------
  77.  
  78.     __Startup__ contains our jump table to the overrides.
  79.     This code must be kept in sync with the assembly jump table
  80.     in NewApp.a and the gxOverrideType resources in NewApp.r
  81.  
  82.     -----------------------------------------------------------------------    */
  83.  
  84. #if defined(__MWERKS__)
  85. asm void __Startup__(void);
  86. asm void __Startup__(void)
  87. {
  88.     DC.L    0                    // Reserved for owner count.
  89.  
  90.     // Raster messages
  91.     JMP SD_RasterDataIn                    // (offset =  4)
  92.  
  93.     // Universal messages
  94.     JMP SD_ImageJob                        // (offset =  8)
  95.     JMP SD_StartSendPage                // (offset =  12)
  96.     JMP SD_FinishSendPage                // (offset =  16)
  97.     JMP SD_SetupImageData                // (offset =  20)
  98.     JMP SD_OpenConnection                // (offset =  24)
  99.     JMP SD_CloseConnection                // (offset =  28)
  100.     JMP SD_CleanupOpenConnection        // (offset =  32)
  101.     JMP SD_BufferData                    // (offset =  36)
  102.     JMP SD_FreeBuffer                    // (offset =  40)
  103.     JMP SD_WriteData                    // (offset =  44)
  104.     JMP SD_DumpBuffer                    // (offset =  48)
  105.     JMP SD_DefaultDesktopPrinter        // (offset =  52)
  106.  
  107.     RTS                            // this is needed so __Startup__ symbol works
  108. }
  109. #endif
  110.  
  111.  
  112. /*    -----------------------------------------------------------------------
  113.  
  114.     SD_RasterDataIn is an override of gxRasterDataIn.  It simply takes the
  115.     bitmap data passed to us, and sends it to the "device" using
  116.     Send_GXBufferData.  For this driver, we're being passed 32-bit XRGB
  117.     data (where "X" indicates an unused alpha byte), stripping off the
  118.     unused byte, and sending it to gxBufferData as RGB data.
  119.     
  120.     If we find that we've moved over blank lines, we call WriteBlankLines
  121.     to send RGB bands of white to gxBufferData.  If your device supports
  122.     it, it is far more economical to skip the white space, rather than
  123.     image it.
  124.  
  125.     -----------------------------------------------------------------------    */
  126.  
  127. OSErr SD_RasterDataIn (gxOffscreenHdl hOffscreen, gxRectangle *bandRect, gxRectangle *dirtyRect)
  128. {
  129.     OSErr                anErr;
  130.     char                lockState;
  131.     gxBitmap            *pBitmap;
  132.     unsigned char        *XRGBDataPtr, *RGBDataPtr, *scanStart;
  133.     long                rowNum, colNum, amtToWrite, numBlankLinesToDo;
  134.     Ptr                    baseAddr;
  135.     DriverGlobalsHdl    drvrGlobalsHdl;
  136.  
  137. #pragma unused (dirtyRect)
  138.  
  139.     // get the globals from the instance handler context
  140.     drvrGlobalsHdl = GetGlobals();
  141.     
  142.     // Update the status display to indicate that we're sending data to the "printer."        
  143.     anErr = GXReportStatus(kTransmissionStatID, kSendingPartStatIdx);
  144.     require(anErr == noErr, ReportStatus_Failed);
  145.  
  146.  
  147.     // Write some blank lines if we need to. 
  148.     numBlankLinesToDo = (bandRect->top >>16) - (*drvrGlobalsHdl)->lastYPos;
  149.     if (numBlankLinesToDo > 0)
  150.     {
  151.         anErr = WriteBlankLines(numBlankLinesToDo, bandRect);
  152.         nrequire(anErr, WriteBlankLines_Failed);
  153.     }
  154.  
  155.     // Make sure the offscreen bitmap is locked down, and then repackage the
  156.     // data.  To save space, we're converting the XRGB data to RGB data in
  157.     // the same imaging buffer that was passed to us.
  158.     lockState = HGetState((Handle) hOffscreen);
  159.     HLockHi((Handle) hOffscreen);
  160.  
  161.     pBitmap = &(*hOffscreen)->thePlanes[0].theBits;
  162.     RGBDataPtr = XRGBDataPtr = (unsigned char *) ((unsigned long) pBitmap->image + (unsigned long) ((bandRect->left >>16) * 4));
  163.     baseAddr = (Ptr) RGBDataPtr;
  164.  
  165.  
  166.     // Convert all data in this raster bitmap to 24-bit RGB.  XRGBData
  167.     // points to the next byte of unconverted data, and RGBDataPtr
  168.     // points to the next place to store the converted RGB data.
  169.  
  170.     for (rowNum = (bandRect->top >>16); rowNum < (bandRect->bottom >>16); rowNum++)
  171.     {
  172.         scanStart = XRGBDataPtr;
  173.         
  174.         for (colNum = (bandRect->left >>16); colNum < (bandRect->right >>16); colNum++)
  175.         {
  176.             ++XRGBDataPtr;                // skip those dang alphas!
  177.             *RGBDataPtr = *XRGBDataPtr;    // copy Red component
  178.             ++RGBDataPtr;
  179.             ++XRGBDataPtr;
  180.             *RGBDataPtr = *XRGBDataPtr;    // copy Green component
  181.             ++RGBDataPtr;
  182.             ++XRGBDataPtr;
  183.             *RGBDataPtr = *XRGBDataPtr;    // copy Blue component
  184.             ++RGBDataPtr;
  185.             ++XRGBDataPtr;
  186.         }
  187.             
  188.         if (rowNum == (bandRect->top >>16))    // 1st row?  Store some things for later.
  189.         {
  190.             (*drvrGlobalsHdl)->pixMapRowBytes = (long) XRGBDataPtr - (long) baseAddr;
  191.             (*drvrGlobalsHdl)->pixMapBounds.bottom += (bandRect->bottom  >>16) - (bandRect->top >>16);
  192.             (*drvrGlobalsHdl)->pixMapBounds.right = (bandRect->right >>16) - (bandRect->left >>16);
  193.         }
  194.  
  195.         // Bump XRGBDataPtr to the start of the next scan line.
  196.         XRGBDataPtr = scanStart + (pBitmap->rowBytes & 0x7FFF);
  197.     }
  198.  
  199.     // Write out the data for this band.
  200.  
  201.     amtToWrite = (long) RGBDataPtr - (long) baseAddr;
  202.     anErr = Send_GXBufferData(baseAddr, amtToWrite, gxNoBufferOptions);
  203.  
  204.     // Reset the handle's lock on the way out, and update our
  205.     // lastYPos variable.
  206.  
  207.     HSetState((Handle) hOffscreen, lockState);
  208.  
  209. WriteBlankLines_Failed:
  210. ReportStatus_Failed:
  211.     (*drvrGlobalsHdl)->lastYPos = (bandRect->bottom >>16) +1;
  212.  
  213.     return anErr;
  214. }
  215.  
  216.  
  217. /*    -----------------------------------------------------------------------
  218.  
  219.     SD_DefaultDesktopPrinter is an override of gxDefaultDesktopPrinter.
  220.     It adds an 'outp' resource to the newly created desktop printer.
  221.     This resource was introduced for QuickDraw GX 1.1, and allows us to
  222.     specify that we don't have paper trays, so paper mismatches and manual
  223.     feed alerts should be suppressed.
  224.  
  225.     -----------------------------------------------------------------------    */
  226.  
  227. OSErr SD_DefaultDesktopPrinter(Str31 dtpName)
  228. {
  229.     OSErr                        anErr;
  230.     gxDriverOutputSettingsHdl    resHdl;
  231.     
  232. //    Forward the message, so the desktop printer creation is completed.
  233.  
  234.     anErr = Forward_GXDefaultDesktopPrinter(dtpName);
  235.     nrequire(anErr, Failed_DefaultDesktopPrinter);
  236.  
  237.  
  238. //    Create a gxDriverOutputSettingsHdl that has the outputSettings
  239. //    field cleared, rather than set to gxCanConfigureTrays.
  240.  
  241.     resHdl = (gxDriverOutputSettingsHdl) NewHandleSysClear(sizeof(gxDriverOutputSettingsHdl));
  242.     require(resHdl, Failed_NewHandleSysClear);
  243.  
  244.  
  245. //    Add the handle to our desktop printer, and then dispose of it.
  246.  
  247.     anErr = GXWriteDTPData(dtpName, gxDriverOutputType, gxDriverOutputTypeID, (Handle) resHdl);
  248.     nrequire(anErr, Failed_WriteDTPResource);
  249.     
  250.     DisposeHandle((Handle) resHdl);
  251.     
  252. Failed_WriteDTPResource:
  253. Failed_NewHandleSysClear:
  254. Failed_DefaultDesktopPrinter:
  255.  
  256.     return anErr;
  257. }
  258.  
  259. /*    -----------------------------------------------------------------------
  260.  
  261.     SD_OpenConnection is an override for gxOpenConnection.  In this routine
  262.     we allocate our custom buffer structures and forward the message to the
  263.     default gxOpenConnection handler.  Since we specify customIO in our
  264.     'iobm' resource, no connection is actually opened.
  265.  
  266.     -----------------------------------------------------------------------    */
  267.  
  268. OSErr SD_OpenConnection()
  269. {
  270.     OSErr    anErr;
  271.     
  272.     // Create our buffers, then forward the message.
  273.  
  274.     anErr = CreateBuffers();
  275.     
  276.     if (!anErr)
  277.         anErr = Forward_GXOpenConnection();
  278.     else
  279.         GXCleanupOpenConnection();
  280.  
  281.     return anErr;
  282. }
  283.  
  284.  
  285. /*    -----------------------------------------------------------------------
  286.  
  287.     SD_CloseConnection is an override for gxCloseConnection.  In this
  288.     routine we forward the message to the default gxCloseConnection
  289.     handler and dispose of our custom buffer structures.
  290.  
  291.     -----------------------------------------------------------------------    */
  292.  
  293. OSErr SD_CloseConnection()
  294. {
  295.     OSErr    anErr;
  296.     
  297.     // Forward the message and dispose of our buffers.
  298.  
  299.     anErr = Forward_GXCloseConnection();
  300.     DisposeBuffers();
  301.  
  302.     return anErr;
  303. }
  304.  
  305.  
  306. /*    -----------------------------------------------------------------------
  307.  
  308.     SD_CleanupOpenConnection is an override for gxCleanupOpenConnection.
  309.     In this routine we forward the message and dispose of our data
  310.     structures that might have been allocated before we got an error in
  311.     our gxOpenConnection code.
  312.  
  313.     -----------------------------------------------------------------------    */
  314.  
  315. void SD_CleanupOpenConnection()
  316. {
  317.     // Forward the message and dispose of our buffers (if any).
  318.  
  319.     Forward_GXCleanupOpenConnection();
  320.     DisposeBuffers();
  321. }
  322.  
  323.  
  324. /*    -----------------------------------------------------------------------
  325.  
  326.     SD_BufferData is an override for the gxBufferData message.  To support
  327.     our custom buffering code, we perform a total override of this message,
  328.     fill up the next available buffer with the data.  We'll store data and,
  329.     if necessary, flush buffers until all of the passed data has been
  330.     processed.
  331.  
  332.     -----------------------------------------------------------------------    */
  333.  
  334. OSErr SD_BufferData(Ptr data, long length, long bufferOptions)  // only override for custom buffering
  335. {
  336.     OSErr                        anErr = noErr;
  337.     register char                *pData = (char *) data;
  338.     register BufferEntryPtr        buffPtr;
  339.     short                        idx, curBuff;
  340.     Boolean                        foundAFreeBuffer;
  341.     long                        dataLeftToStore = length;
  342.     char                        hdlState;
  343.     DriverGlobalsHdl            drvrGlobalsHdl;
  344.     BufferGroupHdl                buffGrpHdl;
  345.     
  346. #pragma unused(bufferOptions)
  347.  
  348.     // get the globals from the instance handler context
  349.     drvrGlobalsHdl = GetGlobals();
  350.     buffGrpHdl = (**drvrGlobalsHdl).buffer;
  351.  
  352.     // Lock the buffer group.
  353.     hdlState = HGetState((Handle) buffGrpHdl);
  354.     HLockHi((Handle) buffGrpHdl);
  355.     
  356.     // While there's no error, and more data to store, process data.
  357.     while (!anErr && (dataLeftToStore > 0))
  358.     {
  359.         // Fill the current buffer with data and indicate that the buffer is dirty.
  360.  
  361.         curBuff = (*buffGrpHdl)->curBuff;
  362.         buffPtr = &(*buffGrpHdl)->buff[curBuff];
  363.  
  364.         while ((dataLeftToStore > 0) && (buffPtr->curOffset < (*buffGrpHdl)->bufferSize))
  365.         {            
  366.             // Move the data to our buffer.
  367.             (*buffPtr->printBuffer)->data[buffPtr->curOffset] = *pData;
  368.             ++(buffPtr->curOffset);
  369.             ++pData;
  370.             --dataLeftToStore;
  371.         }
  372.  
  373.         buffPtr->bufferIsDirty = true;
  374.  
  375.  
  376.         // If dataLeftToStore > 0, it means that we've filled the current buffer,
  377.         // and we need another.  Find a free one.
  378.  
  379.         if (dataLeftToStore > 0)
  380.         {
  381.             foundAFreeBuffer = false;
  382.  
  383.             // If we can find another buffer that's not dirty, we've found a
  384.             // buffer we can store data in.  By specifying numBuffers -1 below,
  385.             // we avoid checking the current buffer, which we know is  dirty.
  386.             for (idx = 0; idx < ((*buffGrpHdl)->numBuffers -1); idx++)
  387.             {
  388.                 // Search up from the last buffer we checked,
  389.                 // wrapping around if necessary.
  390.  
  391.                 ++curBuff;
  392.                 if (curBuff >= (*buffGrpHdl)->numBuffers)
  393.                     curBuff = 0;
  394.                 
  395.                 buffPtr = &(*buffGrpHdl)->buff[curBuff];
  396.  
  397.                 if (!buffPtr->bufferIsDirty)
  398.                 {
  399.                     foundAFreeBuffer = true;
  400.                     break;
  401.                 }
  402.             }
  403.             
  404.             // If there are no free buffers, flush them all and use buffer 0.
  405.             if (!foundAFreeBuffer)
  406.             {
  407.                 anErr = FlushBuffers(buffGrpHdl);
  408.                 curBuff = 0;
  409.             }
  410.             
  411.             // Whatever our current buffer is, store it in our buffer
  412.             // structure.
  413.             (*buffGrpHdl)->curBuff = curBuff;
  414.         }
  415.     }
  416.  
  417.     // Restore the state of the buffer group handle.
  418.     HSetState((Handle) buffGrpHdl, hdlState);
  419.     return anErr;
  420. }
  421.  
  422.  
  423. /*    -----------------------------------------------------------------------
  424.  
  425.     SD_FreeBuffer is an override for the gxFreeBuffer message.  You only
  426.     need to override this message if you're doing asynchronous I/O.  Since
  427.     we're not, this is only here as a reminder for you.  It does nothing
  428.     but forward the message to the default implementation of gxFreeBuffer.
  429.  
  430.     -----------------------------------------------------------------------    */
  431.  
  432. OSErr SD_FreeBuffer(gxPrintingBuffer *theBuffer)
  433. {
  434.     return Forward_GXFreeBuffer(theBuffer);
  435. }
  436.  
  437.  
  438. /*    -----------------------------------------------------------------------
  439.  
  440.     SD_WriteData is an override for gxWriteData.  Here, we flush our custom
  441.     buffers and then write the passed data, if any, to the output file
  442.     using our custom I/O routine, WriteFileData.
  443.  
  444.     -----------------------------------------------------------------------    */
  445.  
  446. OSErr SD_WriteData(Ptr data, long length)
  447. {
  448.     OSErr                        anErr;
  449.     DriverGlobalsHdl            drvrGlobalsHdl;
  450.     BufferGroupHdl                buffGrpHdl;
  451.     
  452.     // get the globals from the instance handler context
  453.     drvrGlobalsHdl = GetGlobals();
  454.     buffGrpHdl = (**drvrGlobalsHdl).buffer;
  455.  
  456.     // Flush the buffers, then do the actual write.
  457.     anErr = FlushBuffers(buffGrpHdl);
  458.     if (!anErr && (data != nil) && (length > 0))
  459.         anErr = WriteFileData(data, length);
  460.  
  461.     return anErr;
  462. }
  463.  
  464.  
  465. /*    -----------------------------------------------------------------------
  466.  
  467.     SD_DumpBuffer is an override for gxDumpBuffer.  Here, we write the
  468.     passed data to the output file using our custom I/O routine,
  469.     WriteFileData.
  470.  
  471.     -----------------------------------------------------------------------    */
  472.  
  473. OSErr SD_DumpBuffer(gxPrintingBuffer *theBuffer)
  474. {
  475.     if (theBuffer->size != 0)
  476.         return WriteFileData(theBuffer->data, theBuffer->size);
  477.     else
  478.         return noErr;
  479. }
  480.  
  481.  
  482. /*    -----------------------------------------------------------------------
  483.  
  484.     SD_ImageJob is an override for gxImageJob.  Here, we create and
  485.     initialize global data that we'll use during imaging.
  486.  
  487.     -----------------------------------------------------------------------    */
  488.  
  489. OSErr SD_ImageJob(gxSpoolFile theSpoolFile, long *closeOptions)
  490. {
  491.     OSErr                anErr;
  492.     FSSpec                anFSSpec;
  493.     short                vRefNum;
  494.     long                dirID, itemSize;
  495.     gxJobInfo            jobInfo;
  496.     Str255                fileName;
  497.     DriverGlobalsHdl    drvrGlobalsHdl;
  498.     
  499.     // Create and store a handle for our global data.
  500.     anErr = CreateGlobals();
  501.     drvrGlobalsHdl = GetGlobals();
  502.  
  503.     // Now, do some more initialization for the first file we'll write to.
  504.  
  505.     if (!anErr)
  506.     {
  507.         // Determine the name of this document, and append ", Page " to it.
  508.         // We'll use this when we create PICT files.  Again, the string
  509.         // should really come from a resource file, for localization
  510.         // reasons.
  511.  
  512.         itemSize = sizeof(gxJobInfo);
  513.         anErr = GetCollectionItem(GXGetJobCollection(GXGetJob()),
  514.                                   gxJobTag, gxPrintingTagID,
  515.                                   &itemSize, &jobInfo);
  516.  
  517.         nrequire(anErr, GetCollectionItemFailed);
  518.  
  519.         if (jobInfo.documentName[0] > 22)    // If necessary, crop file name so we
  520.             jobInfo.documentName[0] = 22;    // have room for our page # stuff.
  521.             
  522.         BlockMove(&jobInfo.documentName[1], &fileName[1], (long) jobInfo.documentName[0]);
  523.         BlockMove(", Page ", &fileName[jobInfo.documentName[0] +1], 7);
  524.  
  525.         // Now make an FSSpec for this file.
  526.  
  527.         FindFolder(kOnSystemDisk, kDesktopFolderType, kCreateFolder, &vRefNum, &dirID);
  528.         fileName[0] = jobInfo.documentName[0] +7;
  529.         FSMakeFSSpec(vRefNum, dirID, fileName, &anFSSpec);
  530.         BlockMove(&anFSSpec, &(*drvrGlobalsHdl)->fileLocation, sizeof(FSSpec));
  531.  
  532.         // Set the number of pages we've imaged to 0.
  533.         (*drvrGlobalsHdl)->pagesImaged = 0;
  534.  
  535.         // With our global data initialized, it's time to forward the
  536.         // gxImageJob message so that the job is processed.
  537.         anErr = Forward_GXImageJob(theSpoolFile, closeOptions);
  538.  
  539.         // All done imaging!  Close the last file, if it's still open,
  540.         // and flush the volume so that we get the changes out to disk
  541.         // faster.
  542.  
  543.         if ((*drvrGlobalsHdl)->curFileRefNum)
  544.             FSClose((*drvrGlobalsHdl)->curFileRefNum);
  545.     
  546.         FlushVol("\p", (*drvrGlobalsHdl)->fileLocation.vRefNum);
  547.         
  548. GetCollectionItemFailed:
  549.  
  550.         // However we get here, dispose of the global data we allocated above.
  551.  
  552.         DisposeGlobals();
  553.     }
  554.  
  555.     return anErr;
  556. }
  557.  
  558.  
  559. /*    -----------------------------------------------------------------------
  560.  
  561.     SD_StartSendPage is an override for gxStartSendPage.  Here, we close
  562.     the current file (if any) and open a new one for the next page.  This
  563.     way, we're able to create a PICT file for each page of a document.
  564.  
  565.     -----------------------------------------------------------------------    */
  566.  
  567. OSErr SD_StartSendPage(gxFormat pageFormat)
  568. {
  569.     OSErr                anErr;
  570.     char                numStr[11], maxChars, nextChar;
  571.     long                numLen;
  572.     DriverGlobalsHdl    drvrGlobalsHdl;
  573.  
  574.     // get the globals from the instance handler context
  575.     drvrGlobalsHdl = GetGlobals();
  576.  
  577.     // Close current file, if any.
  578.     HLockHi((Handle) drvrGlobalsHdl);
  579.     if ((*drvrGlobalsHdl)->curFileRefNum)
  580.     {
  581.         FSClose((*drvrGlobalsHdl)->curFileRefNum); 
  582.         (*drvrGlobalsHdl)->curFileRefNum = (short) nil;
  583.     }
  584.     
  585.     // Bump the number of pages imaged, and use that in the
  586.     // filename for the next page.  We started pagesImaged at
  587.     // 0, so the first filename will have a 1 appended to it.
  588.  
  589.     (*drvrGlobalsHdl)->lastYPos = 0;
  590.     ++(*drvrGlobalsHdl)->pagesImaged;
  591.  
  592.     NumToString((*drvrGlobalsHdl)->pagesImaged, (void *) numStr);
  593.     numLen = (unsigned long) numStr[0];
  594.     maxChars = 31 -numLen; 
  595.  
  596.     if ((*drvrGlobalsHdl)->fileLocation.name[0] > maxChars)
  597.         (*drvrGlobalsHdl)->fileLocation.name[0] = maxChars;
  598.  
  599.     nextChar = (*drvrGlobalsHdl)->fileLocation.name[0] +1;
  600.     BlockMove(&numStr[1], &(*drvrGlobalsHdl)->fileLocation.name[nextChar], numLen);
  601.     (*drvrGlobalsHdl)->fileLocation.name[0] += numLen;
  602.  
  603.  
  604.     // Create a new file for this page, recklessly replacing any
  605.     // existing file with that name.
  606.     FSpDelete(&(*drvrGlobalsHdl)->fileLocation);
  607.     anErr = FSpCreate(&(*drvrGlobalsHdl)->fileLocation, kFileCreator, kFileType, smSystemScript); 
  608.  
  609.     // Open the new file, and write the beginning of the PICT file.
  610.     if (!anErr)
  611.         anErr = FSpOpenDF(&(*drvrGlobalsHdl)->fileLocation, fsCurPerm, &(*drvrGlobalsHdl)->curFileRefNum);
  612.     if (!anErr)
  613.         anErr = WriteStartOfPICTFile();
  614.  
  615.  
  616.     // Initialize this page's PICT's pixmap's bounds to (0,0,0,0).
  617.     (*drvrGlobalsHdl)->pixMapBounds.top = 0;
  618.     (*drvrGlobalsHdl)->pixMapBounds.left = 0;
  619.     (*drvrGlobalsHdl)->pixMapBounds.bottom = 0;
  620.     (*drvrGlobalsHdl)->pixMapBounds.right = 0;
  621.  
  622.  
  623.     // Strip the page number we just added from the file name in our globals.
  624.     // This way, we won't have it when it comes time to set up the file name
  625.     // for the next page.
  626.     (*drvrGlobalsHdl)->fileLocation.name[0] -= numLen;
  627.     HUnlock((Handle) drvrGlobalsHdl);
  628.  
  629.  
  630.     // Finally, forward gxStartSendPage so that GX and any overrides can do
  631.     // whatever they need to do.
  632.  
  633.     if (!anErr)
  634.         anErr = Forward_GXStartSendPage(pageFormat);
  635.  
  636.     return anErr;
  637. }
  638.  
  639.  
  640. /*    -----------------------------------------------------------------------
  641.  
  642.     SD_FinishSendPage is an override for gxFinishSendPage.  Here, we
  643.     forward the gxFinishPage message and write out the end of the PICT
  644.     file we created in SD_StartSendPage.
  645.  
  646.     -----------------------------------------------------------------------    */
  647.  
  648. OSErr SD_FinishSendPage()
  649. {
  650.     OSErr    anErr1, anErr2;
  651.     
  652.     // Forward the gxFinishPage message and write out the
  653.     // remainder of this page's PICT file.
  654.  
  655.     anErr1 = Forward_GXFinishSendPage();
  656.     anErr2 = WriteEndOfPICTFile();
  657.  
  658.     return (anErr1)? anErr1: anErr2;
  659. }
  660.  
  661.  
  662. /*    -----------------------------------------------------------------------
  663.  
  664.     SD_SetupImageData is an override for gxSetupImageData.  Here, we
  665.     forward the gxSetupImageData message and store the resolution for
  666.     the PICTs we'll create.
  667.  
  668.     -----------------------------------------------------------------------    */
  669.  
  670. OSErr SD_SetupImageData(gxRasterImageDataHdl hImageData)
  671. {
  672.     OSErr                anErr;
  673.     DriverGlobalsHdl    drvrGlobalsHdl;
  674.  
  675.     // get the globals from the instance handler context
  676.     drvrGlobalsHdl = GetGlobals();
  677.  
  678.     // Do the default setup.
  679.  
  680.     anErr = Forward_GXSetupImageData(hImageData);
  681.      
  682.     // Set up our PICT resolution based on the information in the
  683.     // gxRasterImageDataHdl that we're passed.
  684.  
  685.     (*drvrGlobalsHdl)->hRes = (*hImageData)->hImageRes;
  686.     (*drvrGlobalsHdl)->vRes = (*hImageData)->vImageRes;
  687.  
  688.     return (anErr);
  689. }
  690.  
  691.  
  692. /*    -----------------------------------------------------------------------
  693.  
  694.     CreateBuffers is the routine which creates and initializes our custom
  695.     buffers.
  696.  
  697.     -----------------------------------------------------------------------    */
  698.  
  699. static OSErr CreateBuffers()
  700. {
  701.     OSErr                        anErr;
  702.     long                        thisBig;
  703.     DriverGlobalsHdl            drvrGlobalsHdl;
  704.     BufferGroupHdl                buffGrpHdl;
  705.     
  706.     // get the globals from the instance handler context
  707.     drvrGlobalsHdl = GetGlobals();
  708.     
  709.     thisBig = sizeof(BufferGroup) +
  710.               (sizeof(BufferEntry) * (kNumBuffs -1));
  711.     
  712.     // Create one handle for our buffer "group" and then individual handles for
  713.     // each buffer in the group.
  714.  
  715.     buffGrpHdl = (BufferGroupHdl) TempNewHandle(thisBig, &anErr);
  716.  
  717.     if (!anErr)
  718.     {
  719.         short    idx;
  720.         Size    ourBufferSize, growDummy;
  721.  
  722.         // Initialize the buffer structure and store the buffer group in
  723.         // our instance context so we can get it later.
  724.         
  725.         (**buffGrpHdl).numBuffers = kNumBuffs;
  726.         (**buffGrpHdl).curBuff = 0;
  727.  
  728.         // We'll make kNumBuffs buffers that use a total of kMaxRAMToUse
  729.         // or kBuffRAMPercentage of the largest available block, whichever
  730.         // is less.
  731.     
  732.         ourBufferSize = (TempMaxMem(&growDummy) * kBuffRAMPercentage) / 100;
  733.         ourBufferSize = (ourBufferSize < kMaxRAMToUse)? ourBufferSize: kMaxRAMToUse;
  734.         ourBufferSize /= kNumBuffs;
  735.  
  736.         // Store the buffer size.  We subtract the size of a gxPrintingBuffer, since
  737.         // the bytes occupied by the gxPrintingBuffer structure are not actually
  738.         // available for storing data.  (Look at the structure if this sounds
  739.         // confusing.)
  740.  
  741.         (**buffGrpHdl).bufferSize = ourBufferSize - sizeof(gxPrintingBuffer);
  742.         
  743.         for (idx = (**buffGrpHdl).numBuffers; idx > 0; idx--)
  744.         {
  745.             OSErr    tempErr = anErr;
  746.  
  747.             (**buffGrpHdl).buff[idx -1].bufferIsDirty = false;
  748.             (**buffGrpHdl).buff[idx -1].curOffset = 0;
  749.             (**buffGrpHdl).buff[idx -1].printBuffer
  750.                     = (gxPrintingBuffer **) TempNewHandle(ourBufferSize, &tempErr);
  751.             
  752.             if (!anErr) anErr = tempErr;    // Don't worry about errors until we leave.
  753.                                             // The caller will send GXCleanupOpenConnection
  754.                                             // if we fail, and that will call DisposeBuffers.
  755.         }
  756.  
  757.         for (idx = (**buffGrpHdl).numBuffers; idx > 0; idx--)
  758.         {
  759.             if ((**buffGrpHdl).buff[idx -1].printBuffer != nil)
  760.                 HLock( (Handle)(**buffGrpHdl).buff[idx -1].printBuffer );
  761.         }
  762.  
  763.         (**drvrGlobalsHdl).buffer = buffGrpHdl;
  764.     }
  765.  
  766.     return anErr;
  767. }
  768.  
  769.  
  770. /*    -----------------------------------------------------------------------
  771.  
  772.     DisposeBuffers is the routine which disposes of our custom buffers.
  773.  
  774.     -----------------------------------------------------------------------    */
  775.  
  776. static OSErr DisposeBuffers ( void )
  777. {
  778.     DriverGlobalsHdl            drvrGlobalsHdl;
  779.     BufferGroupHdl                buffGrpHdl;
  780.     
  781.     // get the globals from the instance handler context
  782.     drvrGlobalsHdl = GetGlobals();
  783.     buffGrpHdl = (**drvrGlobalsHdl).buffer;
  784.  
  785.     // Have we set up them there buffers?  Then erradicate 'em.
  786.     if ( buffGrpHdl != nil )
  787.     {
  788.         short    idx;
  789.         
  790.         // Dispose of any allocated buffers.
  791.  
  792.         for (idx = (**buffGrpHdl).numBuffers; idx > 0; idx--)
  793.         {
  794.             if ((**buffGrpHdl).buff[idx -1].printBuffer != nil)
  795.                 DisposeHandle( (Handle) (**buffGrpHdl).buff[idx -1].printBuffer );
  796.         }
  797.  
  798.         DisposeHandle( (Handle)buffGrpHdl );
  799.         
  800.         // Indicate that we have no buffers.
  801.  
  802.         (**drvrGlobalsHdl).buffer = nil;
  803.     }
  804.  
  805.     return noErr;
  806. }
  807.  
  808.  
  809. /*    -----------------------------------------------------------------------
  810.  
  811.     FlushBuffers is the routine which flushes our custom buffers.  To do
  812.     this, it cycles through each one to see if there's data in it.  If so,
  813.     it sends gxDumpBuffer for the buffer, followed by gxFreeBuffer.
  814.  
  815.     -----------------------------------------------------------------------    */
  816.  
  817. static OSErr FlushBuffers(BufferGroupHdl buffGrpHdl)
  818. {
  819.     OSErr    anErr = noErr;
  820.     short    idx;
  821.     char    hdlState;
  822.  
  823.     // Lock the buffer group.
  824.  
  825.     hdlState = HGetState((Handle) buffGrpHdl);
  826.     HLockHi((Handle) buffGrpHdl);
  827.  
  828.     // Send gxDumpBuffer and gxFreeBuffer for each buffer with data in it.
  829.  
  830.     for (idx = 0; idx < (*buffGrpHdl)->numBuffers; idx++)
  831.     {
  832.         if ((*buffGrpHdl)->buff[idx].bufferIsDirty)
  833.         {
  834.             // gxDumpBuffer will look at printbuffer.size to see how much
  835.             // data to write out.  Set it to the current offset, which just
  836.             // happens to equal the number of bytes we've stored in the buffer.
  837.  
  838.             (*(*buffGrpHdl)->buff[idx].printBuffer)->size =
  839.                 (*buffGrpHdl)->buff[idx].curOffset;
  840.  
  841.  
  842.             // Send gxDumpBuffer and gxFreeBuffer for this buffer.
  843.  
  844.             anErr = Send_GXDumpBuffer(*(*buffGrpHdl)->buff[idx].printBuffer);
  845.  
  846.             if (!anErr)
  847.                 anErr = Send_GXFreeBuffer(*(*buffGrpHdl)->buff[idx].printBuffer);
  848.  
  849.  
  850.             // Clear the buffer's dirty flag and reset its data offset.
  851.  
  852.             (*buffGrpHdl)->buff[idx].bufferIsDirty = false;
  853.             (*buffGrpHdl)->buff[idx].curOffset = 0;
  854.         }
  855.     }
  856.     
  857.     (*buffGrpHdl)->curBuff = 0;
  858.  
  859.     // Restore the state of the buffer group handle.
  860.     HSetState((Handle) buffGrpHdl, hdlState);
  861.     
  862.     return anErr;
  863. }
  864.  
  865.  
  866. /*    -----------------------------------------------------------------------
  867.  
  868.     WriteFileData is a routine that writes the passed data to a file whose
  869.     reference ID is stored in our global data.
  870.  
  871.     -----------------------------------------------------------------------    */
  872.  
  873. static OSErr WriteFileData(void *dataBuffer, long dataLength)
  874. {
  875.     long                amtToWrite = dataLength;
  876.     DriverGlobalsHdl    drvrGlobalsHdl;
  877.  
  878.     // get the globals from the instance handler context
  879.     drvrGlobalsHdl = GetGlobals();
  880.  
  881.     // Write some data to our file.
  882.     return FSWrite((*drvrGlobalsHdl)->curFileRefNum, &amtToWrite, dataBuffer); 
  883. }
  884.  
  885.  
  886. /*    -----------------------------------------------------------------------
  887.  
  888.     WriteStartOfPICTFile is a routine that writes out the start of an
  889.     extended version 2 PICT that only contains a clip and a pixmap.  In
  890.     this routine we write out all the data up to the pixmap data.  However,
  891.     since we won't know things like the bounds and rowbytes until later,
  892.     we simply write out zeroes now, and update everything when we're done
  893.     imaging this page.  We do the updating in the routine
  894.     WriteEndOfPICTFile.
  895.  
  896.     -----------------------------------------------------------------------    */
  897.  
  898. static OSErr WriteStartOfPICTFile ( void )
  899. {
  900.     OSErr    anErr;
  901.     Ptr        dataPtr;
  902.  
  903.     // We need to write out the 512 unused bytes that every PICT file
  904.     // contains, plus 122 bytes that comprise the header and information
  905.     // that precedes the pixel data in our pixmap.  Since we do this at
  906.     // the start of the page, when SD_DumpBuffer and SD_WriteData write
  907.     // data to the file, they'll actually be filling out the pixel data
  908.     // in our PICT's pixmap.
  909.     //
  910.     // Anyway, create a clear pointer that's big enough to hold all the
  911.     // data that precedes our pixmap's pixels.  If there are no errors,
  912.     // write it out via our gxBufferData override.  When done, dispose
  913.     // of the pointer we used.
  914.  
  915.     dataPtr = NewPtrClear(512 +122);
  916.  
  917.     if (!(anErr = MemError()))
  918.     {
  919.         anErr = Send_GXBufferData(dataPtr, 512 +122, gxNoBufferOptions);
  920.         DisposePtr(dataPtr);
  921.     }
  922.  
  923.     return anErr;
  924. }
  925.  
  926.  
  927. /*    -----------------------------------------------------------------------
  928.  
  929.     WriteEndOfPICTFile is a routine that writes out the end of an
  930.     extended version 2 PICT that only contains a clip and a pixmap.  It
  931.     also updates the beginning of the PICT, with information about the
  932.     pixmap's bounds and so forth.  The beginning of the PICT was written
  933.     out with the WriteStartOfPICTFile routine.
  934.     
  935.     Writing out the end of the PICT simply involves writing out the end-
  936.     of-PICT opCode 0x00FF.  Most of the work done in this routine has to
  937.     do with updating the start-of-PICT data that we already wrote out.
  938.     
  939.     -----------------------------------------------------------------------    */
  940.  
  941. static OSErr WriteEndOfPICTFile ( void )
  942. {
  943.     OSErr                anErr;
  944.     Fixed                hRes, vRes, hResScale, vResScale;
  945.     short                finalPictData;
  946.     short                initialPictData[61], curFileRefNum;
  947.     long                index = 0, pictSize;
  948.     Rect                drawRect, a72dpiDrawRect;
  949.     DriverGlobalsHdl    drvrGlobalsHdl;
  950.  
  951.     // get the globals from the instance handler context
  952.     drvrGlobalsHdl = GetGlobals();
  953.  
  954.     // Get the horizontal and vertical resolutions that we imaged
  955.     // at, along with the scaling necessary to apply to 72 dpi
  956.     // viewing rectangles for this image.
  957.     hRes = (*drvrGlobalsHdl)->hRes;
  958.     vRes = (*drvrGlobalsHdl)->vRes;
  959.     hResScale = FixRatio(72, hRes >>16);  // FixRatio(hRes >>16, 72);
  960.     vResScale = FixRatio(72, vRes >>16);  // FixRatio(vRes >>16, 72);
  961.  
  962.     // Get the pixmap's native bounds, and calculate the correct
  963.     // viewing rectangle for 72 dpi.  We pin the top/left corner
  964.     // of each rectangle to 0,0 for convenience.
  965.     drawRect = (*drvrGlobalsHdl)->pixMapBounds;
  966.     OffsetRect(&drawRect, -drawRect.left, -drawRect.top);
  967.     a72dpiDrawRect.top = a72dpiDrawRect.left = 0;
  968.     a72dpiDrawRect.bottom = (FixMul(ff(drawRect.bottom), vResScale) >>16);
  969.     a72dpiDrawRect.right = (FixMul(ff(drawRect.right), hResScale) >>16);
  970.  
  971.     // Flush our buffers. (Yes, since we're doing our own buffer
  972.     // management, we could just call FlushBuffers, but this is how
  973.     // you'd do it otherwise.)
  974.     anErr = Send_GXWriteData(nil, 0);
  975.     nrequire(anErr, FlushBuffersFailed);
  976.  
  977.     // Get the current file's refNum.  Since we flushed the buffers,
  978.     // we can go back and see how big the PICT is.  Do so.
  979.  
  980.     curFileRefNum = (*drvrGlobalsHdl)->curFileRefNum;
  981.     anErr = GetEOF(curFileRefNum, &pictSize);
  982.     nrequire(anErr, GetEOFFailed);
  983.  
  984.     // If necessary, add a $00 to word align the endPict opcode.
  985.     if ((pictSize & 1) != 0)
  986.     {
  987.         finalPictData = 0;
  988.         anErr = Send_GXWriteData((Ptr) &finalPictData, 1);
  989.         nrequire(anErr, WordAlignFailed);
  990.         ++pictSize;
  991.     }
  992.  
  993.     // Write the endPict opcode.
  994.     finalPictData = 0x00FF;
  995.     anErr = Send_GXWriteData((Ptr) &finalPictData, 2);
  996.     nrequire(anErr, SendFinalDataFailed);
  997.  
  998.     // Now, we're ready to update the information that precedes
  999.     // the pixmap data.  Set our file position to 512 bytes from
  1000.     // the start.  That puts us just past the obsolete PICT header
  1001.     // that we're required to include.
  1002.     anErr = SetFPos(curFileRefNum, fsFromStart, 512);
  1003.     nrequire(anErr, SetFPosFailed);
  1004.  
  1005.     // Store the low word of picsize.
  1006.     initialPictData[index] = pictSize & 0xFFFF;
  1007.     ++index;
  1008.  
  1009.     // Store the picFrame at 72 dpi.
  1010.     initialPictData[index] = a72dpiDrawRect.top;
  1011.     ++index;
  1012.     initialPictData[index] = a72dpiDrawRect.left;
  1013.     ++index;
  1014.     initialPictData[index] = a72dpiDrawRect.bottom;
  1015.     ++index;
  1016.     initialPictData[index] = a72dpiDrawRect.right;
  1017.     ++index;
  1018.  
  1019.     // Store the pict version opcode ($0011).
  1020.     initialPictData[index] = 0x0011;
  1021.     ++index;
  1022.  
  1023.     // Store the pict version ($02FF).
  1024.     initialPictData[index] = 0x02FF;
  1025.     ++index;
  1026.  
  1027.     // Store the header opcode ($0C00).
  1028.     initialPictData[index] = 0x0C00;
  1029.     ++index;
  1030.  
  1031.     // Store the header version (-2).
  1032.     initialPictData[index] = -2;
  1033.     ++index;
  1034.  
  1035.     // Store the reserved word (0).
  1036.     initialPictData[index] = 0;
  1037.     ++index;
  1038.  
  1039.     // Store the native horizontal resolution (Fixed) of the source data.
  1040.  
  1041.     initialPictData[index] = hRes >>16;
  1042.     ++index;
  1043.     initialPictData[index] = hRes & 0xFFFF;
  1044.     ++index;
  1045.  
  1046.     // Store the native vertical resolution (Fixed) of the source data.
  1047.  
  1048.     initialPictData[index] = vRes >>16;
  1049.     ++index;
  1050.     initialPictData[index] = vRes & 0xFFFF;
  1051.     ++index;
  1052.  
  1053.     // Store the native source rectangle.
  1054.  
  1055.     initialPictData[index] = drawRect.top;
  1056.     ++index;
  1057.     initialPictData[index] = drawRect.left;
  1058.     ++index;
  1059.     initialPictData[index] = drawRect.bottom;
  1060.     ++index;
  1061.     initialPictData[index] = drawRect.right;
  1062.     ++index;
  1063.  
  1064.     // Store the reserved longword (0L).
  1065.  
  1066.     initialPictData[index] = 0;
  1067.     ++index;
  1068.     initialPictData[index] = 0;
  1069.     ++index;
  1070.  
  1071.     // Store the clip opcode (1).
  1072.  
  1073.     initialPictData[index] = 1;
  1074.     ++index;
  1075.     
  1076.     // Store the size of the clip region data (10).
  1077.  
  1078.     initialPictData[index] = 10;
  1079.     ++index;
  1080.  
  1081.     // Store the clip rectangle.
  1082.  
  1083.     initialPictData[index] = drawRect.top;
  1084.     ++index;
  1085.     initialPictData[index] = drawRect.left;
  1086.     ++index;
  1087.     initialPictData[index] = drawRect.bottom;
  1088.     ++index;
  1089.     initialPictData[index] = drawRect.right;
  1090.     ++index;
  1091.  
  1092.     // Store the opBitsRect opcode ($009A).
  1093.  
  1094.     initialPictData[index] = 0x009A;
  1095.     ++index;
  1096.  
  1097.     // Store the pixmap's baseAddr placeholder (always $000000FF).
  1098.  
  1099.     initialPictData[index] = 0x0000;
  1100.     ++index;
  1101.     initialPictData[index] = 0x00FF;
  1102.     ++index;
  1103.  
  1104.     // Store the rowBytes (high bit must be set for a pixmap).
  1105.  
  1106.     initialPictData[index] = (*drvrGlobalsHdl)->pixMapRowBytes | 0x8000;
  1107.     ++index;
  1108.  
  1109.     // Store the pixmap bounds at source resolution.
  1110.  
  1111.     initialPictData[index] = drawRect.top;
  1112.     ++index;
  1113.     initialPictData[index] = drawRect.left;
  1114.     ++index;
  1115.     initialPictData[index] = drawRect.bottom;
  1116.     ++index;
  1117.     initialPictData[index] = drawRect.right;
  1118.     ++index;
  1119.  
  1120.     // Store the pixmap version (0).
  1121.  
  1122.     initialPictData[index] = 0;
  1123.     ++index;
  1124.  
  1125.     // Store the pixmap packing type (2 == we dropped pad bytes).
  1126.  
  1127.     initialPictData[index] = 2;
  1128.     ++index;
  1129.  
  1130.     // Store the packing size (0L).
  1131.  
  1132.     initialPictData[index] = 0;
  1133.     ++index;
  1134.     initialPictData[index] = 0;
  1135.     ++index;
  1136.  
  1137.     // Store the horizontal resolution (Fixed) of the source data.
  1138.  
  1139.     initialPictData[index] = hRes >>16;
  1140.     ++index;
  1141.     initialPictData[index] = hRes & 0xFFFF;
  1142.     ++index;
  1143.  
  1144.     // Store the vertical resolution (Fixed) of the source data.
  1145.  
  1146.     initialPictData[index] = vRes >>16;
  1147.     ++index;
  1148.     initialPictData[index] = vRes & 0xFFFF;
  1149.     ++index;
  1150.  
  1151.     // Store the pixelType (direct == 16).
  1152.  
  1153.     initialPictData[index] = 16;
  1154.     ++index;
  1155.  
  1156.     // Store the pixelSize (32 (packed to 24) bits per pixel).
  1157.  
  1158.     initialPictData[index] = 32;
  1159.     ++index;
  1160.  
  1161.     // Store the pixel component count (3).
  1162.  
  1163.     initialPictData[index] = 3;
  1164.     ++index;
  1165.  
  1166.     // Store the pixel component size (8).
  1167.  
  1168.     initialPictData[index] = 8;
  1169.     ++index;
  1170.  
  1171.     // Store the offset to next plane (0).
  1172.  
  1173.     initialPictData[index] = 0;
  1174.     ++index;
  1175.     initialPictData[index] = 0;
  1176.     ++index;
  1177.  
  1178.     // Store the ctSeed (0L).
  1179.  
  1180.     initialPictData[index] = 0;
  1181.     ++index;
  1182.     initialPictData[index] = 0;
  1183.     ++index;
  1184.  
  1185.     // Store the ctFlags (0).
  1186.  
  1187.     initialPictData[index] = 0;
  1188.     ++index;
  1189.  
  1190.     // Store the ctSize (-1 == 0 entries.  Unused for direct pixmaps anyway).
  1191.  
  1192.     initialPictData[index] = -1;
  1193.     ++index;
  1194.  
  1195.     // Store the source rectangle at source resolution.
  1196.  
  1197.     initialPictData[index] = drawRect.top;
  1198.     ++index;
  1199.     initialPictData[index] = drawRect.left;
  1200.     ++index;
  1201.     initialPictData[index] = drawRect.bottom;
  1202.     ++index;
  1203.     initialPictData[index] = drawRect.right;
  1204.     ++index;
  1205.  
  1206.     // Store the destination rectangle at source resolution.
  1207.  
  1208.     initialPictData[index] = drawRect.top;
  1209.     ++index;
  1210.     initialPictData[index] = drawRect.left;
  1211.     ++index;
  1212.     initialPictData[index] = drawRect.bottom;
  1213.     ++index;
  1214.     initialPictData[index] = drawRect.right;
  1215.     ++index;
  1216.  
  1217.     // Store the transfer mode (ditherCopy).
  1218.  
  1219.     initialPictData[index] = ditherCopy;
  1220.     ++index;
  1221.  
  1222.     // The number of bytes we've got to write is index *2 (since
  1223.     // we bumped index at every word we stored).  Empirically, this
  1224.     // comes out to 122 bytes, which explains the 122 bytes in
  1225.     // WriteStartOfPICTFile and the 61 words allocated for
  1226.     // initialPictData.  If you change the data that's written into
  1227.     // this file, make sure you update those two values!!
  1228.     //
  1229.     // Write out the updated data.
  1230.  
  1231.     index *= 2;
  1232.     anErr = FSWrite(curFileRefNum, &index, initialPictData); 
  1233.  
  1234. SetFPosFailed:
  1235. SendFinalDataFailed:
  1236. WordAlignFailed:
  1237. GetEOFFailed:
  1238. FlushBuffersFailed:
  1239.  
  1240.     return anErr;
  1241. }
  1242.  
  1243.  
  1244. /*    -----------------------------------------------------------------------
  1245.  
  1246.     WriteBlankLines is a routine used to add blank lines to our output.
  1247.     We use this to add "skipped over" lines to our output from
  1248.     SD_RasterDataIn.  Since we're printing to a file, we need to add the
  1249.     white space as bands of white data.
  1250.  
  1251.     -----------------------------------------------------------------------    */
  1252.  
  1253. static OSErr WriteBlankLines(long numBlankLinesToDo, gxRectangle *bandRect) 
  1254. {
  1255.     OSErr                anErr = noErr;
  1256.     long                line, aByte, lineLength;
  1257.     unsigned char        *blankLine, *whichByte;
  1258.  
  1259.     // Record some "blank lines" in our file.  NOTE: This assumes we output 24-bit RGB data.
  1260.  
  1261.     if (numBlankLinesToDo > 0)
  1262.     {
  1263.         // Create a pointer to hold one white (0xFF, 0xFF, 0xFF…) line.
  1264.  
  1265.         lineLength = 3 * ((bandRect->right >>16) - (bandRect->left >> 16));
  1266.         blankLine = (unsigned char *) NewPtrSys(lineLength);
  1267.         anErr = MemError();
  1268.         nrequire(anErr, NewPtrSys_Failed);
  1269.  
  1270.         // Make it white.
  1271.  
  1272.         for (aByte = 0, whichByte = blankLine; aByte < lineLength; aByte++, whichByte++)
  1273.             *whichByte = 0xFF;
  1274.  
  1275.         // Write it to the file as many times as necessary, then dispose of our pointer.
  1276.  
  1277.         for (line = 0; line < numBlankLinesToDo; line++)
  1278.             anErr = Send_GXBufferData((Ptr) blankLine, lineLength, gxNoBufferOptions);
  1279.  
  1280.         DisposePtr((Ptr) blankLine);
  1281.     }
  1282.  
  1283. NewPtrSys_Failed:
  1284.     return anErr; 
  1285. }
  1286.  
  1287.  
  1288.  
  1289.  
  1290.